// xiosbase internal header (from <ios>)
#pragma once
#ifndef _XIOSBASE_
#define _XIOSBASE_
#ifndef RC_INVOKED
#include <share.h>
#include <system_error>
#include <xlocale>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

#define _OPENPROT _SH_DENYNO

_STD_BEGIN
#define _IOSskipws 0x0001
#define _IOSunitbuf 0x0002
#define _IOSuppercase 0x0004
#define _IOSshowbase 0x0008
#define _IOSshowpoint 0x0010
#define _IOSshowpos 0x0020
#define _IOSleft 0x0040
#define _IOSright 0x0080
#define _IOSinternal 0x0100
#define _IOSdec 0x0200
#define _IOSoct 0x0400
#define _IOShex 0x0800
#define _IOSscientific 0x1000
#define _IOSfixed 0x2000

#define _IOShexfloat 0x3000 // added with TR1

#define _IOSboolalpha 0x4000
#define _IOS_Stdio 0x8000

#define _IOS_Nocreate 0x40
#define _IOS_Noreplace 0x80
#define _IOSbinary 0x20

// CLASS TEMPLATE _Iosb
template <class _Dummy>
class _Iosb { // define templatized bitmask/enumerated types, instantiate on demand
public:
    enum _Dummy_enum { _Dummy_enum_val = 1 }; // don't ask
    enum _Fmtflags { // constants for formatting options
        _Fmtmask = 0xffff,
        _Fmtzero = 0
    };

    static constexpr _Fmtflags skipws     = (_Fmtflags) _IOSskipws;
    static constexpr _Fmtflags unitbuf    = (_Fmtflags) _IOSunitbuf;
    static constexpr _Fmtflags uppercase  = (_Fmtflags) _IOSuppercase;
    static constexpr _Fmtflags showbase   = (_Fmtflags) _IOSshowbase;
    static constexpr _Fmtflags showpoint  = (_Fmtflags) _IOSshowpoint;
    static constexpr _Fmtflags showpos    = (_Fmtflags) _IOSshowpos;
    static constexpr _Fmtflags left       = (_Fmtflags) _IOSleft;
    static constexpr _Fmtflags right      = (_Fmtflags) _IOSright;
    static constexpr _Fmtflags internal   = (_Fmtflags) _IOSinternal;
    static constexpr _Fmtflags dec        = (_Fmtflags) _IOSdec;
    static constexpr _Fmtflags oct        = (_Fmtflags) _IOSoct;
    static constexpr _Fmtflags hex        = (_Fmtflags) _IOShex;
    static constexpr _Fmtflags scientific = (_Fmtflags) _IOSscientific;
    static constexpr _Fmtflags fixed      = (_Fmtflags) _IOSfixed;

    static constexpr _Fmtflags hexfloat = (_Fmtflags) _IOShexfloat; // added with TR1 (not in C++11)

    static constexpr _Fmtflags boolalpha   = (_Fmtflags) _IOSboolalpha;
    static constexpr _Fmtflags _Stdio      = (_Fmtflags) _IOS_Stdio;
    static constexpr _Fmtflags adjustfield = (_Fmtflags)(_IOSleft | _IOSright | _IOSinternal);
    static constexpr _Fmtflags basefield   = (_Fmtflags)(_IOSdec | _IOSoct | _IOShex);
    static constexpr _Fmtflags floatfield  = (_Fmtflags)(_IOSscientific | _IOSfixed);

    enum _Iostate { // constants for stream states
        _Statmask = 0x17
    };

    static constexpr _Iostate goodbit = (_Iostate) 0x0;
    static constexpr _Iostate eofbit  = (_Iostate) 0x1;
    static constexpr _Iostate failbit = (_Iostate) 0x2;
    static constexpr _Iostate badbit  = (_Iostate) 0x4;

    enum _Openmode { // constants for file opening options
        _Openmask = 0xff
    };

    static constexpr _Openmode in         = (_Openmode) 0x01;
    static constexpr _Openmode out        = (_Openmode) 0x02;
    static constexpr _Openmode ate        = (_Openmode) 0x04;
    static constexpr _Openmode app        = (_Openmode) 0x08;
    static constexpr _Openmode trunc      = (_Openmode) 0x10;
    static constexpr _Openmode _Nocreate  = (_Openmode) _IOS_Nocreate;
    static constexpr _Openmode _Noreplace = (_Openmode) _IOS_Noreplace;
    static constexpr _Openmode binary     = (_Openmode) _IOSbinary;

    enum _Seekdir { // constants for file positioning options
        _Seekbeg,
        _Seekcur,
        _Seekend
    };

    static constexpr _Seekdir beg = _Seekbeg;
    static constexpr _Seekdir cur = _Seekcur;
    static constexpr _Seekdir end = _Seekend;

    enum { // constant for default file opening protection
        _Openprot = _OPENPROT
    };
};

template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::skipws;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::unitbuf;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::uppercase;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showbase;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showpoint;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showpos;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::left;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::right;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::internal;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::dec;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::oct;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::hex;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::scientific;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::fixed;

template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::hexfloat; // added with TR1 (not in C++11)

template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::boolalpha;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::_Stdio;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::adjustfield;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::basefield;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::floatfield;

template <class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::goodbit;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::eofbit;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::failbit;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::badbit;

template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::in;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::out;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::ate;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::app;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::trunc;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::_Nocreate;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::_Noreplace;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::binary;

template <class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::beg;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::cur;
template <class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::end;

// CLASS ios_base
class _CRTIMP2_PURE_IMPORT ios_base : public _Iosb<int> { // base class for ios
public:
    using fmtflags = int;
    using iostate  = int;
    using openmode = int;
    using seekdir  = int;

#if _HAS_OLD_IOSTREAMS_MEMBERS
    using streamoff = _STD streamoff;
    using streampos = _STD streampos;
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    enum event { // constants for ios events
        erase_event,
        imbue_event,
        copyfmt_event
    };

    using event_callback = void(__CLRCALL_OR_CDECL*)(event, ios_base&, int);

#if _HAS_OLD_IOSTREAMS_MEMBERS
    using io_state  = unsigned int;
    using open_mode = unsigned int;
    using seek_dir  = unsigned int;
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    // CLASS failure
    class failure

        : public system_error { // base of all iostreams exceptions
    public:
        explicit failure(const string& _Message, const error_code& _Errcode = make_error_code(io_errc::stream))
            : system_error(_Errcode, _Message) { // construct with message
        }

        explicit failure(const char* _Message, const error_code& _Errcode = make_error_code(io_errc::stream))
            : system_error(_Errcode, _Message) { // construct with message
        }


#if _HAS_EXCEPTIONS

#else // _HAS_EXCEPTIONS
    protected:
        virtual void _Doraise() const { // report the exception
            _RAISE(*this);
        }
#endif // _HAS_EXCEPTIONS
    };

    // CLASS Init
    class _CRTIMP2_PURE_IMPORT Init { // controller for standard-stream initialization
    public:
        __CLR_OR_THIS_CALL Init() { // initialize standard streams on first construction
            _Init_ctor(this);
        }

        __CLR_OR_THIS_CALL ~Init() noexcept { // flush standard streams on last destruction
            _Init_dtor(this);
        }

    private:
        static _MRTIMP2_NPURE void __cdecl _Init_ctor(Init*);
        static _MRTIMP2_NPURE void __cdecl _Init_dtor(Init*);

        __PURE_APPDOMAIN_GLOBAL static int _Init_cnt; // net ctor count

        static _MRTIMP2_NPURE int& __cdecl _Init_cnt_func();
    };

    explicit __CLR_OR_THIS_CALL operator bool() const { // test if no stream operation has failed
        return !fail();
    }

    _NODISCARD bool __CLR_OR_THIS_CALL operator!() const { // test if any stream operation has failed
        return fail();
    }

    void __CLR_OR_THIS_CALL clear(iostate _State, bool _Reraise) { // set state, possibly reraise exception
        _State &= _Statmask;
        _Mystate             = _State;
        const auto _Filtered = _State & _Except;
        if (_Filtered) {
            if (_Reraise) {
                _RERAISE;
            }

            const char* _Msg;
            if (_Filtered & ios_base::badbit) {
                _Msg = "ios_base::badbit set";
            } else if (_Filtered & ios_base::failbit) {
                _Msg = "ios_base::failbit set";
            } else {
                _Msg = "ios_base::eofbit set";
            }

            _THROW(failure(_Msg));
        }
    }

    void __CLR_OR_THIS_CALL clear(iostate _State = goodbit) { // set state to argument
        clear(_State, false);
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    void __CLR_OR_THIS_CALL clear(io_state _State) { // set state to argument, old-style
        clear((iostate) _State);
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    _NODISCARD iostate __CLR_OR_THIS_CALL rdstate() const { // return stream state
        return _Mystate;
    }

    void __CLR_OR_THIS_CALL setstate(
        iostate _State, bool _Exreraise) { // merge in state argument, possibly reraise exception
        clear(rdstate() | _State, _Exreraise);
    }

    void __CLR_OR_THIS_CALL setstate(iostate _State) { // merge in state argument
        clear(rdstate() | _State, false);
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    void __CLR_OR_THIS_CALL setstate(io_state _State) { // merge in state argument, old style
        setstate((iostate) _State);
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    _NODISCARD bool __CLR_OR_THIS_CALL good() const { // test if no state bits are set
        return rdstate() == ios_base::goodbit;
    }

    _NODISCARD bool __CLR_OR_THIS_CALL eof() const { // test if eofbit is set in stream state
        return rdstate() & ios_base::eofbit;
    }

    _NODISCARD bool __CLR_OR_THIS_CALL fail() const { // test if badbit or failbit is set in stream state
        return rdstate() & (ios_base::badbit | ios_base::failbit);
    }

    _NODISCARD bool __CLR_OR_THIS_CALL bad() const { // test if badbit is set in stream state
        return rdstate() & ios_base::badbit;
    }

    _NODISCARD iostate __CLR_OR_THIS_CALL exceptions() const { // return exception mask
        return _Except;
    }

    void __CLR_OR_THIS_CALL exceptions(iostate _Newexcept) { // set exception mask to argument
        _Except = _Newexcept & _Statmask;
        clear(rdstate());
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    void __CLR_OR_THIS_CALL exceptions(io_state _State) { // set exception mask to argument, old style
        exceptions((iostate) _State);
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    _NODISCARD fmtflags __CLR_OR_THIS_CALL flags() const { // return format flags
        return _Fmtfl;
    }

    fmtflags __CLR_OR_THIS_CALL flags(fmtflags _Newfmtflags) { // set format flags to argument
        const fmtflags _Oldfmtflags = _Fmtfl;
        _Fmtfl                      = _Newfmtflags & _Fmtmask;
        return _Oldfmtflags;
    }

    fmtflags __CLR_OR_THIS_CALL setf(fmtflags _Newfmtflags) { // merge in format flags argument
        const ios_base::fmtflags _Oldfmtflags = _Fmtfl;
        _Fmtfl |= _Newfmtflags & _Fmtmask;
        return _Oldfmtflags;
    }

    fmtflags __CLR_OR_THIS_CALL setf(
        fmtflags _Newfmtflags, fmtflags _Mask) { // merge in format flags argument under mask argument
        const ios_base::fmtflags _Oldfmtflags = _Fmtfl;
        _Fmtfl                                = (_Oldfmtflags & ~_Mask) | (_Newfmtflags & _Mask & _Fmtmask);
        return _Oldfmtflags;
    }

    void __CLR_OR_THIS_CALL unsetf(fmtflags _Mask) { // clear format flags under mask argument
        _Fmtfl &= ~_Mask;
    }

    _NODISCARD streamsize __CLR_OR_THIS_CALL precision() const { // return precision
        return _Prec;
    }

    streamsize __CLR_OR_THIS_CALL precision(streamsize _Newprecision) { // set precision to argument
        const streamsize _Oldprecision = _Prec;
        _Prec                          = _Newprecision;
        return _Oldprecision;
    }

    _NODISCARD streamsize __CLR_OR_THIS_CALL width() const { // return width
        return _Wide;
    }

    streamsize __CLR_OR_THIS_CALL width(streamsize _Newwidth) { // set width to argument
        const streamsize _Oldwidth = _Wide;
        _Wide                      = _Newwidth;
        return _Oldwidth;
    }

    _NODISCARD locale __CLR_OR_THIS_CALL getloc() const { // get locale
        return *_Ploc;
    }

    locale __CLR_OR_THIS_CALL imbue(const locale& _Loc) { // set locale to argument
        locale _Oldlocale = *_Ploc;
        *_Ploc            = _Loc;
        _Callfns(imbue_event);
        return _Oldlocale;
    }

    _NODISCARD static int __CLRCALL_OR_CDECL xalloc() { // allocate new iword/pword index
        _BEGIN_LOCK(_LOCK_STREAM) // lock thread to ensure atomicity
        return _Index++;
        _END_LOCK()
    }

    _NODISCARD long& __CLR_OR_THIS_CALL iword(int _Idx) { // return reference to long element
        return _Findarr(_Idx)._Lo;
    }

    _NODISCARD void*& __CLR_OR_THIS_CALL pword(int _Idx) { // return reference to pointer element
        return _Findarr(_Idx)._Vp;
    }

    void __CLR_OR_THIS_CALL register_callback(event_callback _Pfn,
        int _Idx) { // register event handler
        _Calls = new _Fnarray(_Idx, _Pfn, _Calls);
    }

    ios_base& __CLR_OR_THIS_CALL copyfmt(const ios_base& _Other) { // copy format stuff
        if (this != _STD addressof(_Other)) { // copy all but _Mystate
            _Tidy();
            *_Ploc          = *_Other._Ploc;
            _Fmtfl          = _Other._Fmtfl;
            _Prec           = _Other._Prec;
            _Wide           = _Other._Wide;
            _Iosarray* _Ptr = _Other._Arr;

            for (_Arr = nullptr; _Ptr != nullptr; _Ptr = _Ptr->_Next) {
                if (_Ptr->_Lo != 0 || _Ptr->_Vp != nullptr) { // copy over nonzero array values
                    iword(_Ptr->_Index) = _Ptr->_Lo;
                    pword(_Ptr->_Index) = _Ptr->_Vp;
                }
            }

            for (_Fnarray* _Pfa = _Other._Calls; _Pfa != nullptr; _Pfa = _Pfa->_Next) {
                register_callback(_Pfa->_Pfn, _Pfa->_Index);
            }

            _Callfns(copyfmt_event); // call callbacks
            exceptions(_Other._Except); // cause any throw at end
        }
        return *this;
    }

    static bool __CLRCALL_OR_CDECL sync_with_stdio(
        bool _Newsync = true) { // set C/C++ synchronization flag from argument
        _BEGIN_LOCK(_LOCK_STREAM) // lock thread to ensure atomicity
        const bool _Oldsync = _Sync;
        _Sync               = _Newsync;
        return _Oldsync;
        _END_LOCK()
    }

    void __CLR_OR_THIS_CALL swap(ios_base& _Right) { // swap with _Right
        if (this != _STD addressof(_Right)) { // different, do the move
            _STD swap(_Mystate, _Right._Mystate);
            _STD swap(_Except, _Right._Except);
            _STD swap(_Fmtfl, _Right._Fmtfl);
            _STD swap(_Prec, _Right._Prec);
            _STD swap(_Wide, _Right._Wide);

            _STD swap(_Arr, _Right._Arr);
            _STD swap(_Calls, _Right._Calls);
            _STD swap(_Ploc, _Right._Ploc);
        }
    }

    virtual __CLR_OR_THIS_CALL ~ios_base() noexcept { // destroy the object
        _Ios_base_dtor(this);
    }

    static _MRTIMP2_PURE_NPURE void __CLRCALL_PURE_OR_CDECL _Addstd(ios_base*); // add standard stream

    size_t _Stdstr; // if > 0 index of standard stream to suppress destruction

protected:
    __CLR_OR_THIS_CALL ios_base() { // default constructor
    }

    void __CLR_OR_THIS_CALL _Init() { // initialize a new ios_base
        _Ploc   = nullptr;
        _Stdstr = 0;
        _Except = goodbit;
        _Fmtfl  = (fmtflags)(skipws | dec);
        _Prec   = 6;
        _Wide   = 0;
        _Arr    = nullptr;
        _Calls  = nullptr;
        clear(goodbit);
        _Ploc = new locale;
    }

private:
    // STRUCT _Iosarray
    struct _Iosarray : public _Crt_new_delete { // list element for open-ended sparse array of longs/pointers
    public:
        __CLR_OR_THIS_CALL _Iosarray(int _Idx, _Iosarray* _Link)
            : _Next(_Link), _Index(_Idx), _Lo(0), _Vp(nullptr) { // construct node for index _Idx and link it in
        }

        _Iosarray* _Next; // pointer to next node
        int _Index; // index of this node
        long _Lo; // stored long value
        void* _Vp; // stored pointer value
    };

    // STRUCT _Fnarray
    struct _Fnarray : public _Crt_new_delete { // list element for open-ended sparse array of event handlers
        __CLR_OR_THIS_CALL _Fnarray(int _Idx, event_callback _Pnew, _Fnarray* _Link)
            : _Next(_Link), _Index(_Idx), _Pfn(_Pnew) { // construct node for index _Idx and link it in
        }

        _Fnarray* _Next; // pointer to next node
        int _Index; // index of this node
        event_callback _Pfn; // pointer to event handler
    };

    void __CLR_OR_THIS_CALL _Callfns(event _Ev) { // call all event handlers, reporting event
        for (_Fnarray* _Pfa = _Calls; _Pfa != nullptr; _Pfa = _Pfa->_Next) {
            (*_Pfa->_Pfn)(_Ev, *this, _Pfa->_Index);
        }
    }

    _Iosarray& __CLR_OR_THIS_CALL _Findarr(int _Idx) { // locate or make a variable array element
        _Iosarray *_Ptr1, *_Ptr2;

        for (_Ptr1 = _Arr, _Ptr2 = nullptr; _Ptr1 != nullptr; _Ptr1 = _Ptr1->_Next) {
            if (_Ptr1->_Index == _Idx) {
                return *_Ptr1; // found element, return it
            } else if (_Ptr2 == nullptr && _Ptr1->_Lo == 0 && _Ptr1->_Vp == nullptr) {
                _Ptr2 = _Ptr1; // found recycling candidate
            }
        }

        if (_Ptr2 != nullptr) { // recycle existing element
            _Ptr2->_Index = _Idx;
            return *_Ptr2;
        }

        _Arr = new _Iosarray(_Idx, _Arr); // make a new element
        return *_Arr;
    }

    void __CLR_OR_THIS_CALL _Tidy() noexcept { // discard storage for an ios_base
        _Callfns(erase_event);
        _Iosarray *_Ptr1, *_Ptr2;

        for (_Ptr1 = _Arr; _Ptr1 != nullptr; _Ptr1 = _Ptr2) { // delete array element
            _Ptr2 = _Ptr1->_Next;
            delete _Ptr1;
        }
        _Arr = nullptr;

        _Fnarray *_Pfa1, *_Pfa2;
        for (_Pfa1 = _Calls; _Pfa1 != nullptr; _Pfa1 = _Pfa2) { // delete callback element
            _Pfa2 = _Pfa1->_Next;
            delete _Pfa1;
        }
        _Calls = nullptr;
    }

    iostate _Mystate; // stream state
    iostate _Except; // exception mask
    fmtflags _Fmtfl; // format flags
    streamsize _Prec; // field precision
    streamsize _Wide; // field width
    _Iosarray* _Arr; // pointer to first node of long/pointer array
    _Fnarray* _Calls; // pointer to first node of call list
    locale* _Ploc; // pointer to locale

    __PURE_APPDOMAIN_GLOBAL static int _Index;
    __PURE_APPDOMAIN_GLOBAL static bool _Sync;

    static _MRTIMP2_PURE_NPURE void __CLRCALL_PURE_OR_CDECL _Ios_base_dtor(ios_base*);

public:
    ios_base(const ios_base&) = delete;
    ios_base& operator=(const ios_base&) = delete;
};
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _XIOSBASE_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
